#include <click/config.h>
#include "codedblock.hh"
#include "matrix.hh"

#include <click/straccum.hh>

CLICK_DECLS



/* do you want to process the data blocks not just the coefficients? */
#define PROCESS_DATA 1
#define XOR	1

GaloisField<8> gf256;

/**
 * copy coefficients only
 */

CodedBlock::~CodedBlock() {
    delete[] _coeff;
    if(_copy) delete[] _data;
}

/**
 * this += a * cb
 * in the finite field
 */
void CodedBlock::add(const CodedBlock &cb, uchar a) {
    massert(a != 0, "%d", a);
    // combine the encoding vectors
    unsigned i = cb._first;
    uchar *d = _coeff + i;
    uchar *s = cb._coeff + i;

    //click_chatter("%s + %d * \n%s = \n", print().c_str(), (uint)a, cb.print().c_str());
    for(; i < _k; ++i, ++d, ++s) {
        *d ^= __field_mul(*s, a);
    }
    update();
    //click_chatter("%s\n", print().c_str());

    if(_datasize == 0)
        // no data, we're done
        return;

    massert(_datasize == cb._datasize, "%d == %d", _datasize, cb._datasize);


#if PROCESS_DATA
    // now do the same thing on the data
    d = _data;
    s = cb._data;

    for(i = cb._datasize; i > 0; --i, ++s, ++d) {
#if XOR
    	*d ^=*s;
#else
        *d ^= __field_mul(*s, a);
#endif
    }
#endif
}


/**
 *  this /= a
 */
void CodedBlock::div(uchar a) {
    massert(a != 0, "%d", a);
    if (a == 1)
        return;
    a = __field_inv(a);
    uchar *d = _coeff + _first;
    for(unsigned i = _first; i < _k; ++i, ++d) {
        *d = __field_mul(*d, a);
    }
#if PROCESS_DATA
    d = _data;
    for(unsigned i = _datasize; i > 0; --i, ++d) {
        *d = __field_mul(*d, a);
    }
#endif
}

/**
 * do GE on block using the PartialGEMatrix
 */
void CodedBlock::add_all(const PartialGEMatrix &m) {
    for(unsigned i = _first; i < _k; ++i) {
        if(_coeff[i] && m[i]) {
            add(*m[i], _coeff[i]);
        }
    }
}

String CodedBlock::print() const {
    StringAccum sa;
    for (unsigned i = 0; i < _k; ++i ) {
        if(i == _first)
            sa << ">";
        else
            sa << " ";
        sa << (uint)_coeff[i];
    }
    sa << " " ;//<< _datasize;
    sa.append(_data,_datasize);
    return sa.take_string();
}



CLICK_ENDDECLS
ELEMENT_PROVIDES(CodedBlock)

